package com.example.threadtest.utils;

import java.io.*;

/**
 * @author 越
 * @createDate 2021-04-01 14:46
 * @desc
 */
public class FileUtil {

    /**
     * 按照字节流的方式读取文件内容（二进制任意文件）
     *
     * Step 1.根据文件路径，构建文件对象
     * Step 2.创建输入流用来读取文件内容
     * Step 3.创建字节数组来存放读取内容
     * Step 4.关闭读取文件的输入流
     *
     * @return
     */
    public static void readFileByFileInputStream(String filePath,String fileName) {
        System.out.println("=== readFileByFileInputStream Start ===");
        // 构建文件对象
        File inputFile = new File(filePath+fileName);
        // 初始化输入流
        InputStream inputStream = null;
        try {
            // 创建字节输入流
            inputStream = new FileInputStream(inputFile);
            // 读取到1KB字节数组中
            byte[] buffer = new byte[1024];
            // 每次读取的字节数
            int readLength;
            // 读取数据并放到buffer数组中
            while ((readLength = inputStream.read(buffer)) != -1) {
                // UTF-8为变长编码，一个汉字占3个字节
                System.out.println("本次读取" + readLength + "个字节数据内容为:" + new String(buffer));
            }
        } catch (IOException e) {
            // 文件未找到时异常处理
            e.printStackTrace();
        }// 读取过程中，删除文件会出此异常
        finally {
            if (inputStream != null) {
                try {
                    // 关闭流过程，也有可能出现异常
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== readFileByFileInputStream End ===");
    }
    /**
     * 通过字节流的方式写入信息到文件（二进制任意文件）
     *
     * Step 1.根据文件路径，构建文件对象
     * Step 2.创建字节输出流写出信息到文件
     * Step 3.构造待写出的内容，并转为字节数组
     * Step 4.关闭读取文件的字符输出流
     */
    public static void writeFileByFileOutputStream(String filePath,String fileName) {
        System.out.println("=== writeFileByFileOutputStream Start ===");
        // 创建写出文件
        File file = new File(filePath+fileName);
        // 初始化字节输出流
        OutputStream outputStream = null;
        // 写出内容
        String outInfo = "写出测试";
        // 转成字节数组
        byte[] byteArray = outInfo.getBytes();
        try {
            // 创建输出字节流
            outputStream = new FileOutputStream(file);
            outputStream.write(byteArray);
            System.out.println("按照字节流成功写出内容："+outInfo);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    // 关闭写出流时，注意抓异常
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== writeFileByFileOutputStream End ===");
    }

    /**
     * 按照字符流的方式读取文件内容
     *
     * Step 1.根据文件路径，构建文件对象
     * Step 2.创建字符输入流读取文件内容
     * Step 3.创建字符数组来存放读取内容
     * Step 4.关闭读取文件的字符输入流
     *
     * @return
     */
    public static void readFileByFileReader(String filePath,String fileName){
        System.out.println("=== readFileByFileReader Start ===");
        // 根据路径拿到文件对象
        File file = new File( filePath+fileName);
        // 初始化字符输入流
        Reader fileReader = null;
        // 初始化存放读取内容的字符数组
        char[] charArray = new char[100];
        // 初始化一个字符
        char once;
        try {
            fileReader = new FileReader(file);
            // 一次读取一个数组长度的字符串
            fileReader.read(charArray);
            System.out.println(charArray);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null) {
                try {
                    // 关闭流过程，也有可能出现异常
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== readFileByFileReader End ===");
    }



    /**
     * 通过字符流的方式写入信息到文件
     *
     * Step 1.根据文件路径，构建文件对象
     * Step 2.创建字符输出流写出信息到文件
     * Step 3.构造待写出的内容，并转为字符数组
     * Step 4.关闭读取文件的字符输出流
     */
    public static void writeFileByFileWriter(String filePath,String fileName){
        System.out.println("=== writeFileByFileWriter Start ===");
        // 创建写出文件
        File file = new File(filePath+fileName);
        // 初始化字符输出流
        Writer fileWriter = null;
        String strInfo = "字符写出数据";
        try {
            // 创建输出字符流
            fileWriter = new FileWriter(file);
            // 写出内容
            fileWriter.write(strInfo);
            System.out.println("按照字符流成功写出内容："+strInfo);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fileWriter != null){
                try {
                    // 关闭写出流时，注意抓异常
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== writeFileByFileWriter End ===");
    }

    /**
     * 任意读取文件内容
     */
    public static void randomAccessFile(String filePath,String fileName){
        System.out.println("=== randomAccessFile Start ===");
        File file = new File(filePath+fileName);
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"r");
            // 获取文件当前的指针位置
            System.out.println("file now pointer is "+randomAccessFile.getFilePointer());
            // 将文件指针设置到指定位置（绝对位置）
            randomAccessFile.seek(3);
            // 相对位置，相对于当前的位置，
            randomAccessFile.skipBytes(3);
            System.out.println("file now pointer is "+randomAccessFile.getFilePointer());
            // 字节数组
            byte[] buffer = new byte[17];
            // off是指的写到buffer的数组的起始位置
            randomAccessFile.read(buffer,0,buffer.length);
            System.out.println(new String(buffer));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("=== randomAccessFile End ===");
    }

    /**
     * 通过字节流的方式将文件内容拷贝到另一个文件中
     *
     * Step 1.根据文件路径，构建源文件对象
     * Step 2.根据文件路径，构造目的文件对象
     * Step 3.创建字节输入流从源文件中读取信息
     * Step 4.将读入到内存的信息再写出到目的文件中
     * Step 5.拷贝完成后关闭输入输出流
     */
    public static void copyFile(String readFilePath,String readFileName,String writeFilePath,String writeFileName) {
        System.out.println("=== copyFile Start ===");
        // 输入文件对象
        File inFile = new File(readFilePath+readFileName);
        if(!fileExists(inFile)){
            throw new RuntimeException("输入的文件不存在");
        }
        // 输出文件对象
        File outFile = new File(writeFilePath+writeFileName);
        if(!pathExists(outFile)){
            makeDir(outFile,true);
        }
        // 初始化输入流
        InputStream inputStream = null;
        // 初始化输出流
        OutputStream outputStream = null;
        try {
            // 将输入流怼到输入文件，使程序内存与磁盘建立联系
            inputStream = new FileInputStream(inFile);
            // 将输出流怼到输出文件，使程序内存与磁盘建立联系
            outputStream = new FileOutputStream(outFile);
            while (true) {
                // 读取信息到内存
                int temp = inputStream.read();
                // 拷贝完成
                if (temp == -1) {
                    break;
                }
                // 将内容拷贝到输出文件中
                outputStream.write(temp);
            }
            System.out.println("拷贝文件成功完成");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 关闭输入流异常后，也要保证输出流关闭
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        System.out.println("=== copyFile End ===");
    }

    /**
     * 从文件的完整路径名（路径+文件名）中提取 路径（包括：Drive+Directroy )
     *
     * @param _sFilePathName 文件的完整路径名（路径+文件名）
     * @return 路径
     */
    public static String extractFilePath(String _sFilePathName) {
        int nPos = _sFilePathName.lastIndexOf('/');
        if (nPos < 0) {
            nPos = _sFilePathName.lastIndexOf('\\');
        }
        return (nPos >= 0 ? _sFilePathName.substring(0, nPos + 1) : "");
    }

    /**
     * 从文件的完整路径名（路径+文件名）中提取文件名(包含扩展名)
     * 如：d:\path\file.ext --> file.ext
     *
     * @param _sFilePathName 文件的完整路径名
     * @return 文件名
     */
    public static String extractFileName(String _sFilePathName) {
        return extractFileName(_sFilePathName, File.separator);
    }
    /**
     * 从文件的完整路径名（路径+文件名）中提取文件名(包含扩展名)
     * 如：d:\path\file.ext --> file.ext
     *
     * @param _sFilePathName  全文件路径名
     * @param _sFileSeparator 文件分隔符
     * @return 文件名
     */
    public static String extractFileName(String _sFilePathName,String _sFileSeparator) {
        int nPos = -1;
        if (_sFileSeparator == null) {
            nPos = _sFilePathName.lastIndexOf(File.separatorChar);
            if (nPos < 0) {
                nPos = _sFilePathName
                        .lastIndexOf(File.separatorChar == '/' ? '\\' : '/');
            }
        } else {
            nPos = _sFilePathName.lastIndexOf(_sFileSeparator);
        }

        if (nPos < 0) {
            return _sFilePathName;
        }

        return _sFilePathName.substring(nPos + 1);
    }
    /**
     * 检查指定文件的路径是否存在
     *
     * @param _sPathFileName 文件名称(含路径）
     * @return 若存在，则返回true；否则，返回false
     */
    public static boolean pathExists(String _sPathFileName) {
        String sPath = extractFilePath(_sPathFileName);
        return fileExists(sPath);
    }
    /**
     * 检查指定文件的路径是否存在
     *
     * @param file 文件
     * @return 若存在，则返回true；否则，返回false
     */
    public static boolean pathExists(File file) {
        String path = file.getPath();
        String name = file.getName();
        System.out.println("path="+path);
        System.out.println("name="+name);
        return pathExists(path+name);
    }
    /**
     * 检查指定文件是否存在
     *
     * @param _sPathFileName 文件全路径
     * @return 若存在，则返回true；否则，返回false
     */
    public static boolean fileExists(String _sPathFileName) {
        File file = new File(_sPathFileName);
        return fileExists(file);
    }
    /**
     * 检查指定文件是否存在
     *
     * @param file 文件
     * @return 若存在，则返回true；否则，返回false
     */
    public static boolean fileExists(File file) {
        return file.exists();
    }

    /**
     * 创建目录
     *
     * @param filePathAndName    文件名称
     * @param isCreateParentDir 如果父目录不存在，是否创建父目录
     * @return
     */
    public static boolean makeDir(String filePathAndName, boolean isCreateParentDir) {
        boolean zResult = false;
        File file = new File(filePathAndName);
        if (isCreateParentDir)
            zResult = file.mkdirs(); // 如果父目录不存在，则创建所有必需的父目录
        else
            zResult = file.mkdir(); // 如果父目录不存在，不做处理
        if (!zResult)
            zResult = file.exists();
        return zResult;
    }
    /**
     * 创建目录
     *
     * @param file    文件
     * @param isCreateParentDir 如果父目录不存在，是否创建父目录
     * @return
     */
    public static boolean makeDir(File file,boolean isCreateParentDir) {
        boolean zResult = false;
        if (isCreateParentDir)
            zResult = file.mkdirs(); // 如果父目录不存在，则创建所有必需的父目录
        else
            zResult = file.mkdir(); // 如果父目录不存在，不做处理
        if (!zResult)
            zResult = file.exists();
        return zResult;
    }

    /**
     * 移除字符串中的BOM前缀
     *
     * @param _sLine 需要处理的字符串
     * @return 移除BOM后的字符串.
     */
    private static String removeBomHeaderIfExists(String _sLine) {
        if (_sLine == null) {
            return null;
        }
        String line = _sLine;
        if (line.length() > 0) {
            char ch = line.charAt(0);
            // 使用while是因为用一些工具看到过某些文件前几个字节都是0xfffe.
            // 0xfeff,0xfffe是字节序的不同处理.JVM中,一般是0xfeff
            while ((ch == 0xfeff || ch == 0xfffe)) {
                line = line.substring(1);
                if (line.length() == 0) {
                    break;
                }
                ch = line.charAt(0);
            }
        }
        return line;
    }


}
